乘风破浪,遇见最美Windows 11之现代Windows桌面应用开发

您所在的位置:网站首页 c 桌面应用开发 乘风破浪,遇见最美Windows 11之现代Windows桌面应用开发

乘风破浪,遇见最美Windows 11之现代Windows桌面应用开发

2023-08-28 06:18| 来源: 网络整理| 查看: 265

什么是C++中的Windows桌面应用程序

https://learn.microsoft.com/zh-cn/cpp/windows/desktop-applications-visual-cpp

用C++编写的桌面应用程序是一个本地应用程序,它可以访问全套的Windows API,并在窗口或系统控制台中运行。用C++编写的桌面应用程序可以在Windows XP到Windows 11上运行(尽管Windows XP已不再得到官方支持,而且有许多Windows API是在那之后引入的)。

桌面应用程序与通用Windows平台(UWP)应用程序不同,后者可以在运行Windows 11、Windows 10、XBox、Windows Phone、Surface Hub和其他设备的PC上运行。

什么是Windows API

https://docs.microsoft.com/zh-cn/cpp/windows/walkthrough-creating-windows-desktop-applications-cpp

Windows API(也被称为Win32 API、Windows桌面API和Windows经典API)是一个基于C语言的框架,用于创建Windows应用程序。它自20世纪80年代以来一直存在,几十年来一直被用来创建Windows应用程序。更高级和更容易编程的框架已经建立在Windows API之上,例如,MFC、ATL、.NET框架。 即使是用C++/WinRT编写的UWP和Store应用程序的最现代的Windows Runtime代码也使用Windows API的底层。

先决条件

一台运行微软Windows 7或更高版本的计算机。我们建议使用Windows 10或更高版本以获得最佳的开发体验。

一份Visual Studio的拷贝。关于如何下载和安装Visual Studio的信息,请参见安装Visual Studio。当你运行安装程序时,确保勾选了用C++进行桌面开发(Desktop development with C++) 的工作负载。如果你在安装Visual Studio时没有安装这个工作负载,不要担心。你可以再次运行安装程序,现在就安装它。

image

Visual Studio安装程序中使用C++的桌面开发工作负载的细节。

了解使用Visual Studio IDE的基本知识。如果你以前使用过Windows桌面应用程序,你可能可以跟上。有关介绍,请参见Visual Studio IDE功能之旅。

对C++语言的基础知识有足够的了解,可以跟着学。别担心,我们不会做太复杂的事情。

创建一个Windows桌面项目

https://github.com/TaylorShi/DemoForCppDesktop

按照这些步骤来创建你的第一个Windows桌面项目。在你进行的过程中,你将为一个工作的Windows桌面应用程序输入代码。要查看你喜欢的Visual Studio版本的文档,请使用版本选择器控件。它位于本页面目录的顶部

要在Visual Studio中创建一个Windows桌面项目 在主菜单中,选择"文件(File)">"新建(New)">"项目(Project)",打开"创建新项目(Create a New Project)"的对话框。

image

image

在对话框的顶部,将"语言(Language)"设置为"C++",将"平台(Platform)"设置为"Windows",并将"项目类型(Project type)"设置为"桌面(Desktop)"。

image

从过滤后的项目类型列表中,选择"Windows桌面向导(Windows Desktop Wizard)",然后选择"下一步(Next)"。在下一页,为项目输入一个名称,例如,"DemoForCppDesktop"。

image

选择"创建(Create)"按钮来创建项目。

image

现在出现"Windows桌面项目(Windows Desktop Project)"对话框。在"应用程序类型(Application type)"下,选择"桌面应用程序(Desktop application)(.exe)"。在"其他选项(Additional options)"下,选择"空项目(Empty project)"。选择"确定(OK)"来创建这个项目。

image

image

在"解决方案资源管理器(Solution Explorer)"中,右键单击"DemoForCppDesktop"项目,选择"添加(Add)",然后选择"新建项(New Item)"。

image

在"添加新项(Add New Item)"对话框中,选择"C++文件(C++ File)(.cpp)"。在"名称(Name)"框中,键入一个文件名,例如,HelloWindowsDesktop.cpp。选择"添加(Add)"。

image

image

现在你的项目已经创建,你的源文件在编辑器中被打开。要继续,请跳到创建代码。

创建代码

接下来,你将学习如何在Visual Studio中创建一个Windows桌面应用程序的代码。

要启动一个Windows桌面应用程序 就像每个C语言程序和C++程序都必须有一个main函数作为其起点一样,每个Windows桌面程序都必须有一个WinMain函数。WinMain的语法如下。 int WINAPI WinMain( _In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nCmdShow );

image

有关该函数的参数和返回值的信息,见WinMain入口点。

所有这些额外的词,如WINAPI,或CALLBACK,或HINSTANCE,或_In_,都是什么?传统的Windows API广泛使用类型化定义和预处理器宏来抽象出类型和平台特定代码的一些细节,如调用约定、__declspec声明和编译器语义。在Visual Studio中,你可以使用IntelliSense快速信息功能来查看这些类型定义和宏的定义。将鼠标悬停在感兴趣的词上,或者选择它并按下Ctrl+K、Ctrl+I,就会弹出一个包含定义的小窗口。欲了解更多信息,请参见使用智能提示。参数和返回类型经常使用SAL注释来帮助你发现编程错误。欲了解更多信息,请参阅使用SAL注释来减少C/C++代码缺陷。

Windows桌面程序需要.定义了TCHAR宏,如果你的项目中定义了UNICODE符号,它最终会解析为wchar_t,否则会解析为char。如果你总是在启用UNICODE的情况下构建,你就不需要TCHAR,可以直接使用wchar_t。 #include #include 除了WinMain函数外,每个Windows桌面应用程序还必须有一个窗口程序函数。这个函数通常被命名为WndProc,但你可以随心所欲地命名它。WndProc的语法如下。 LRESULT CALLBACK WndProc( _In_ HWND hWnd, _In_ UINT message, _In_ WPARAM wParam, _In_ LPARAM lParam );

image

在这个函数中,你写代码来处理事件发生时应用程序从Windows收到的消息。例如,如果用户在你的应用程序中选择了一个OK按钮,Windows将向你发送一条消息,你可以在WndProc函数中编写代码,做任何适当的工作。这就是所谓的处理一个事件。你只处理与你的应用程序有关的事件。

欲了解更多信息,请参见窗口程序。

为了给WinMain函数增加功能 在WinMain函数中,你填充了一个WNDCLASSEX类型的结构。该结构包含关于窗口的信息:应用程序的图标、窗口的背景颜色、显示在标题栏中的名称,以及其他一些东西。重要的是,它包含一个指向你的窗口程序的函数指针。下面的例子显示了一个典型的WNDCLASSEX结构。 WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = LoadIcon(wcex.hInstance, IDI_APPLICATION); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wcex.lpszMenuName = NULL; wcex.lpszClassName = szWindowClass; wcex.hIconSm = LoadIcon(wcex.hInstance, IDI_APPLICATION);

关于上述结构的字段信息,见WNDCLASSEX。

向Windows注册WNDCLASSEX,这样它就知道你的窗口以及如何向它发送消息。使用RegisterClassEx函数,并将窗口类结构作为参数传递。使用_T宏,因为我们使用TCHAR类型。 if (!RegisterClassEx(&wcex)) { MessageBox(NULL, _T("Call to RegisterClassEx failed!"), _T("Windows Desktop Guided Tour"), NULL); return 1; } 现在你可以创建一个窗口。使用CreateWindowEx函数。 static TCHAR szWindowClass[] = _T("DesktopApp"); static TCHAR szTitle[] = _T("Windows Desktop Guided Tour Application"); // The parameters to CreateWindowEx explained: // WS_EX_OVERLAPPEDWINDOW : An optional extended window style. // szWindowClass: the name of the application // szTitle: the text that appears in the title bar // WS_OVERLAPPEDWINDOW: the type of window to create // CW_USEDEFAULT, CW_USEDEFAULT: initial position (x, y) // 500, 100: initial size (width, length) // NULL: the parent of this window // NULL: this application does not have a menu bar // hInstance: the first parameter from WinMain // NULL: not used in this application HWND hWnd = CreateWindowEx( WS_EX_OVERLAPPEDWINDOW, szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 500, 100, NULL, NULL, hInstance, NULL ); if (!hWnd) { MessageBox(NULL, _T("Call to CreateWindowEx failed!"), _T("Windows Desktop Guided Tour"), NULL); return 1; }

这个函数返回一个HWND,它是一个窗口的句柄。一个句柄有点像一个指针,Windows用它来跟踪打开的窗口。欲了解更多信息,请参见Windows数据类型。

在这一点上,窗口已经被创建,但我们仍然需要告诉Windows使其可见。这就是这段代码的作用: // The parameters to ShowWindow explained: // hWnd: the value returned from CreateWindow // nCmdShow: the fourth parameter from WinMain ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd);

显示的窗口没有什么内容,因为你还没有实现WndProc函数。换句话说,应用程序还没有处理Windows现在向它发送的信息。

为了处理这些消息,我们首先添加一个消息循环来监听Windows发送的消息。当应用程序收到一个消息时,这个循环将其分派给你的WndProc函数来处理。该消息循环类似于以下代码。 MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return (int) msg.wParam;

关于消息循环中的结构和函数的更多信息,请参见MSG, GetMessage, TranslateMessage, 和DispatchMessage。

在这一点上,WinMain函数应该类似于以下代码。

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = LoadIcon(wcex.hInstance, IDI_APPLICATION); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wcex.lpszMenuName = NULL; wcex.lpszClassName = szWindowClass; wcex.hIconSm = LoadIcon(wcex.hInstance, IDI_APPLICATION); if (!RegisterClassEx(&wcex)) { MessageBox(NULL, _T("Call to RegisterClassEx failed!"), _T("Windows Desktop Guided Tour"), NULL); return 1; } // Store instance handle in our global variable hInst = hInstance; // The parameters to CreateWindowEx explained: // WS_EX_OVERLAPPEDWINDOW : An optional extended window style. // szWindowClass: the name of the application // szTitle: the text that appears in the title bar // WS_OVERLAPPEDWINDOW: the type of window to create // CW_USEDEFAULT, CW_USEDEFAULT: initial position (x, y) // 500, 100: initial size (width, length) // NULL: the parent of this window // NULL: this application dows not have a menu bar // hInstance: the first parameter from WinMain // NULL: not used in this application HWND hWnd = CreateWindowEx( WS_EX_OVERLAPPEDWINDOW, szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 500, 100, NULL, NULL, hInstance, NULL ); if (!hWnd) { MessageBox(NULL, _T("Call to CreateWindow failed!"), _T("Windows Desktop Guided Tour"), NULL); return 1; } // The parameters to ShowWindow explained: // hWnd: the value returned from CreateWindow // nCmdShow: the fourth parameter from WinMain ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); // Main message loop: MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return (int) msg.wParam; } 为了给WndProc函数增加功能 为了使WndProc函数能够处理应用程序收到的消息,实现一个switch语句。

要处理的一个重要消息是WM_PAINT消息。当其显示的窗口的一部分必须被更新时,应用程序就会收到WM_PAINT消息。当用户把一个窗口移到你的窗口前面,然后又把它移开,这个事件就会发生。你的应用程序不知道这些事件何时发生。只有Windows知道,所以它用WM_PAINT消息来通知你的应用程序。当窗口第一次被显示时,所有的窗口都必须被更新。

要处理一个WM_PAINT消息,首先要调用BeginPaint,然后处理所有的逻辑来布置窗口中的文本、按钮和其他控件,然后调用EndPaint。对于应用程序来说,在开始调用和结束调用之间的逻辑在窗口中显示字符串 "你好,Windows桌面!"。在下面的代码中,TextOut函数被用来显示这个字符串。

PAINTSTRUCT ps; HDC hdc; TCHAR greeting[] = _T("Hello, Windows desktop!"); switch (message) { case WM_PAINT: hdc = BeginPaint(hWnd, &ps); // Here your application is laid out. // For this introduction, we just print out "Hello, Windows desktop!" // in the top left corner. TextOut(hdc, 5, 5, greeting, _tcslen(greeting)); // End application-specific layout section. EndPaint(hWnd, &ps); break; }

代码中的HDC是一个设备上下文的句柄,用于在窗口的客户区绘图。使用BeginPaint和EndPaint函数来准备和完成客户端区域的绘制。BeginPaint返回用于在客户端区域绘图的显示设备上下文的句柄;EndPaint结束绘图请求并释放设备上下文。

一个应用程序通常会处理许多其他的消息。例如,当一个窗口第一次被创建时,WM_CREATE,当窗口关闭时,WM_DESTROY。下面的代码显示了一个基本但完整的WndProc函数。 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { PAINTSTRUCT ps; HDC hdc; TCHAR greeting[] = _T("Hello, Windows desktop!"); switch (message) { case WM_PAINT: hdc = BeginPaint(hWnd, &ps); // Here your application is laid out. // For this introduction, we just print out "Hello, Windows desktop!" // in the top left corner. TextOut(hdc, 5, 5, greeting, _tcslen(greeting)); // End application specific layout section. EndPaint(hWnd, &ps); break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); break; } return 0; } 构建代码

正如承诺的那样,这里是工作程序的完整代码。

要建立这个例子 在编辑器中删除你在HelloWindowsDesktop.cpp中输入的任何代码。复制此示例代码,然后将其粘贴到HelloWindowsDesktop.cpp中。 // HelloWindowsDesktop.cpp // compile with: /D_UNICODE /DUNICODE /DWIN32 /D_WINDOWS /c #include #include #include #include // Global variables // The main window class name. static TCHAR szWindowClass[] = _T("DesktopApp"); // The string that appears in the application's title bar. static TCHAR szTitle[] = _T("Windows Desktop Guided Tour Application"); // Stored instance handle for use in Win32 API calls such as FindResource HINSTANCE hInst; // Forward declarations of functions included in this code module: LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain( _In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nCmdShow ) { WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = LoadIcon(wcex.hInstance, IDI_APPLICATION); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wcex.lpszMenuName = NULL; wcex.lpszClassName = szWindowClass; wcex.hIconSm = LoadIcon(wcex.hInstance, IDI_APPLICATION); if (!RegisterClassEx(&wcex)) { MessageBox(NULL, _T("Call to RegisterClassEx failed!"), _T("Windows Desktop Guided Tour"), NULL); return 1; } // Store instance handle in our global variable hInst = hInstance; // The parameters to CreateWindowEx explained: // WS_EX_OVERLAPPEDWINDOW : An optional extended window style. // szWindowClass: the name of the application // szTitle: the text that appears in the title bar // WS_OVERLAPPEDWINDOW: the type of window to create // CW_USEDEFAULT, CW_USEDEFAULT: initial position (x, y) // 500, 100: initial size (width, length) // NULL: the parent of this window // NULL: this application does not have a menu bar // hInstance: the first parameter from WinMain // NULL: not used in this application HWND hWnd = CreateWindowEx( WS_EX_OVERLAPPEDWINDOW, szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 500, 100, NULL, NULL, hInstance, NULL ); if (!hWnd) { MessageBox(NULL, _T("Call to CreateWindow failed!"), _T("Windows Desktop Guided Tour"), NULL); return 1; } // The parameters to ShowWindow explained: // hWnd: the value returned from CreateWindow // nCmdShow: the fourth parameter from WinMain ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); // Main message loop: MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return (int) msg.wParam; } // FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM) // // PURPOSE: Processes messages for the main window. // // WM_PAINT - Paint the main window // WM_DESTROY - post a quit message and return LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { PAINTSTRUCT ps; HDC hdc; TCHAR greeting[] = _T("Hello, Windows desktop!"); switch (message) { case WM_PAINT: hdc = BeginPaint(hWnd, &ps); // Here your application is laid out. // For this introduction, we just print out "Hello, Windows desktop!" // in the top left corner. TextOut(hdc, 5, 5, greeting, _tcslen(greeting)); // End application-specific layout section. EndPaint(hWnd, &ps); break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); break; } return 0; } 在"构建(Build)"菜单上,选择"构建解决方案(Build Solution)"。编译的结果应该出现在Visual Studio的"输出(Output)"窗口中。

image

要运行该应用程序,按F5。一个包含"Hello, Windows desktop!"文字的窗口应该出现在显示屏的左上角。

image

恭喜你!你已经完成了本攻略,并建立了一个传统的Windows桌面应用程序。你已经完成了本攻略并建立了一个传统的Windows桌面应用程序。

通过命令行编译本机C++程序 创建Hello.cpp

image

添加如下内容:

#include using namespace std; int main() { cout


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3